package com.test.limit;

import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

/**
 * @author zxs
 * @since 2020/06/29
 */
@Service("rateLimiter")
public class RateLimiter implements Limiter{

    private final Map<String, Rate> rateMap = new HashMap<>();

    @Override
    public boolean isAllow(String key, Integer maxCount, Integer period) {
        Rate rate = rateMap.computeIfAbsent(key, (k) -> new Rate(maxCount, maxCount / period));
        return rate.acquire(1);
    }

    static class Rate{
        //最大令牌
        private long maxPermits;

        //当前令牌数
        private long storedPermits;

        //每秒生成多少个令牌
        private long stableIntervalSeconds;

        private long lastSyncTs;

        public Rate(long maxPermits, long stableIntervalSeconds) {
            this.maxPermits = maxPermits;
            this.storedPermits = 10;
            this.stableIntervalSeconds = stableIntervalSeconds;
            lastSyncTs = System.currentTimeMillis();
        }

        //生成令牌
        public void resync() {
            long now = System.currentTimeMillis();
            long durationSeconds = (now - lastSyncTs)/1000;
            //数字过大
            if (durationSeconds < 0) {
                storedPermits = maxPermits;
            }
            if (durationSeconds == 0) {
                return;
            }
            long generateTokens = durationSeconds * stableIntervalSeconds;
            System.out.println("generateTokens: "+generateTokens);
            if(generateTokens+storedPermits>maxPermits){
                storedPermits=maxPermits;
                lastSyncTs=System.currentTimeMillis();
                return;
            }
            storedPermits+=generateTokens;
            lastSyncTs=System.currentTimeMillis();
        }

        //需要令牌数
        public boolean acquire(long num){
            resync();
            System.out.println(this.storedPermits);
            if(storedPermits<num){
                return false;
            }
            storedPermits-=num;
            return true;
        }
    }

}
